from django.shortcuts import render
from django.views import View
from django.http import JsonResponse

import json
from django_redis import get_redis_connection
from goods.models import SKU
from meiduo_mall.utils.cookiesecret import CookieSecret

# Create your views here.


class CartsView(View):

    # 新增购物车
    # POST + /carts/
    def post(self, request):
        # 1、提取参数
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected', True) # 默认添加商品是勾选的

        # 2、校验参数
        if not all([sku_id, count]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'})

        try:
            sku = SKU.objects.get(pk=sku_id)
            count = int(count) # 如果强转异常，说明有可能传来的count="ythytjl"，是错误的
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '参数有误'})

        # 3、业务数据处理
        user = request.user # User对象 或 Anonymouse对象
        if user.is_authenticated:
            # ===========登陆，写redis========
            conn = get_redis_connection('carts')
            # (1)、hash对象，记录商品及其数量
            # conn.hset('carts_%s'%user.id, sku_id, count) # 注意：使用hset添加键值对，如果存在则覆盖，不符合业务
            # hincrby：如果键存在则值累加，如果键不存在则新建插入
            conn.hincrby('carts_%s'%user.id, sku_id, count)
            # (2)、set对象，记录勾选状态
            if selected:
                # 加入集合表示勾选
                conn.sadd('selected_%s'%user.id, sku_id)
            else:
                # 从集合中剔除，表示取消勾选
                conn.srem('selected_%s' % user.id, sku_id)
            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        else:
            # ===========未登陆，写cookie========
            # (1)、提取cookie中的购物车加密字符串数据
            cookie_str = request.COOKIES.get('carts') # carts是业务中统一约定的用户记录cookie购物车加密字符串的key
            # (2)、判断购物车加密字符串数据存在与否
            if cookie_str:
                # 解密
                cart_dict = CookieSecret.loads(cookie_str)
            else:
                # 新建 —— 初始化一个空的字典数据，用于后续构造购物车字典数据
                cart_dict = {}
            # (3)、新增购物车
            if sku_id in cart_dict: # 判断sku_id这个键在cart_dict中是否存在
                # count累加
                cart_dict[sku_id]['count'] += count
                cart_dict[sku_id]['selected'] = selected
            else:
                # 新插入
                cart_dict[sku_id] = {
                    'count': count,
                    'selected': selected
                }
            # (4)、新的购物车字典数据加密写入cookie
            new_cookie_str = CookieSecret.dumps(cart_dict)
            response = JsonResponse({'code': 0, 'errmsg': 'ok'})
            response.set_cookie('carts', new_cookie_str)
            return response

    # 展示购物车
    # GET + /carts/
    def get(self, request):
        # 1、提取参数
        user = request.user
        # 2、校验参数
        # 3、业务数据处理
        # 事先定义变量，用于记录后续读取的购物车字典数据 —— 该字典是购物车字典结构
        # cart_dict = {1:{"count":3, "selected":True}}
        cart_dict = {}

        if user.is_authenticated:
            # 登陆，获取redis购物车数据 —— 组织称购物车字典存储在cart_dict变量中
            conn = get_redis_connection('carts')
            # (1)、读取sku_id和数量
            # redis_carts = {b"1": b"3"}
            redis_carts = conn.hgetall('carts_%s'%user.id)
            # (2)、读取选中状态
            # redis_selected = [b'1']
            redis_selected = conn.smembers('selected_%s'%user.id)
            # (3)、构造购物车字典数据
            for k,v in redis_carts.items():
                sku_id = int(k) # b'1' --> 1
                count = int(v) # b'3' --> 3
                cart_dict[sku_id] = {
                    "count": count,
                    "selected": k in redis_selected
                }
        else:
            # 未登陆获取cookie购物车数据
            cookie_str = request.COOKIES.get('carts')
            if cookie_str:
                cart_dict = CookieSecret.loads(cookie_str)

        # 进一步从mysql中获取sku详细信息，构造响应参数
        cart_skus = [] # 记录返回的响应参数
        for sku_id, v in cart_dict.items(): # cart_dict = {1:{"count":3, "selected":True}}
            sku = SKU.objects.get(pk=sku_id)
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'count': v["count"],
                'selected': v['selected']
            })

        # 4、构建响应
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_skus': cart_skus})

    # 更新购物车
    # PUT+ /carts/
    def put(self, request):
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected', True)

        if not all([sku_id, count]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'})

        try:
            sku = SKU.objects.get(pk=sku_id)
            count = int(count)  # 如果强转异常，说明有可能传来的count="ythytjl"，是错误的
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '参数有误'})

        # 业务数据处理
        new_cookie_str = None # 用于记录未登陆状态下的新购物车加密字符串
        user = request.user
        if user.is_authenticated:
            # 登陆，修改redis购物车
            conn = get_redis_connection('carts')
            # (1)、修改数量
            conn.hset('carts_%s'%user.id, sku_id, count) # 幂等操作，覆盖写入
            # (2)、修改选中状态
            if selected:
                conn.sadd('selected_%s'%user.id, sku_id)
            else:
                conn.srem('selected_%s'%user.id, sku_id)
        else:
            # 未登陆，修改cookie购物车
            # (1)、获取cookie购物车加密字符串
            cookie_str = request.COOKIES.get('carts')
            # (2)、解密字符串得到购物车字典数据
            if cookie_str:
                cart_dict = CookieSecret.loads(cookie_str)
            else:
                cart_dict = {}
            # (3)、修改cart_dict数据，重新加密写入cookie中
            if sku_id in cart_dict:
                cart_dict[sku_id]['count'] = count
                cart_dict[sku_id]['selected'] = selected
            new_cookie_str = CookieSecret.dumps(cart_dict)

        # 构造响应参数
        sku = SKU.objects.get(pk=sku_id)
        cart_sku = {
            'id': sku.id,
            'count': count,
            'selected': selected,
            'name': sku.name,
            'default_image_url': sku.default_image.url,
            'price': sku.price,
            'amount': sku.price * count
        }

        response = JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'cart_sku': cart_sku
        })

        # new_cookie_str变量起到了标志作用：如果是None说明登陆；如果是加密字符串说明未登陆；
        if new_cookie_str:
            response.set_cookie('carts', new_cookie_str)

        return response

    # 删除购物车指定sku_id数据
    # DELETE /carts/
    def delete(self, request):
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        if not sku_id:
            return JsonResponse({'code':400, 'errmsg': '缺少必要参数'})
        try:
            sku = SKU.objects.get(pk=sku_id)
        except SKU.DoesNotExist as e:
            return JsonResponse({'code':400, 'errmsg': 'sku商品不存在'})

        user = request.user
        new_cookie_str = None
        if user.is_authenticated:
            # TODO: 用户登陆，删除redis购物车
            conn = get_redis_connection('carts')
            # (1)、删除hash指定sku_id商品及其count
            conn.hdel('carts_%s'%user.id, sku_id)
            # (2)、删除set中的sku_id
            conn.srem('selected_%s'%user.id, sku_id)
        else:
            # TODO: 用户未登陆删除cookie购物车
            # (1)、读取cookie购物车加密字符串
            cookie_str = request.COOKIES.get('carts')
            # (2)、解密出购物车字典数据
            if cookie_str:
                cart_dict = CookieSecret.loads(cookie_str)
            else:
                cart_dict = {}
            # (3)、删除指定cart_dict中的sku_id键值对
            if sku_id in cart_dict:
                # del cart_dict[sku_id]
                cart_dict.pop(sku_id)
            # (4)、重新加密购物车字典数据
            new_cookie_str = CookieSecret.dumps(cart_dict)

        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        if new_cookie_str:
            response.set_cookie('carts', new_cookie_str)
        return response


class CartsSelectAllView(View):

    # 全选/取消全选
    # PUT + /carts/selection/
    def put(self, request):
        data = json.loads(request.body.decode())
        selected = data.get('selected') # None
        if not isinstance(selected, bool):
            return JsonResponse({'code': 400, 'errmsg': '参数有误'})

        user = request.user
        if user.is_authenticated:
            # TODO: 登陆，把redis购物车全部设置为选中或取消全选
            conn = get_redis_connection('carts')
            # (1)、获取hash购物车sku_id
            # sku_ids = [b'1', b'2']
            sku_ids = conn.hkeys('carts_%s'%user.id)
            # (2)、全选则加入set，取消选项则从set中剔除
            if selected:
                conn.sadd('selected_%s'%user.id, *sku_ids)
            else:
                conn.srem('selected_%s' % user.id, *sku_ids)
            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        else:
            # TODO: 未登陆，把cookie购物车数据全部设置为选中或取消全选
            # (1)、获取cookie购物车加密字符串
            cookie_str = request.COOKIES.get('carts')
            # (2)、解密获取购物车字典数据
            if cookie_str:
                cart_dict = CookieSecret.loads(cookie_str)
            else:
                cart_dict = {}
            # cart_dict = {1:{"count":3, "selected": True}, 2:{"count":31, "selected": False}}
            # (3)、设置全选或取消全选
            sku_ids = cart_dict.keys()
            for sku_id in sku_ids:
                cart_dict[sku_id]['selected'] = selected # True全选，False取消全选
            # (4)、新的加密字符串写入cookie
            new_cookie_str = CookieSecret.dumps(cart_dict)
            response = JsonResponse({'code': 0, 'errmsg': 'ok'})
            response.set_cookie('carts', new_cookie_str)
            return response























